package com.lining.orangeservice.filter;

import com.lining.orangeservice.utils.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT认证过滤器
 * 
 * 作用：拦截所有HTTP请求，检查请求头中的JWT Token，并进行身份验证
 * 继承OncePerRequestFilter确保每个请求只被处理一次
 * 使用@RequiredArgsConstructor实现构造函数注入，简化代码
 */
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    /**
     * JWT工具类，用于解析和验证JWT Token
     * 使用final修饰，通过@RequiredArgsConstructor自动注入
     */
    private final JwtUtil jwtUtil;

    /**
     * 用户详情服务，用于加载用户信息
     * 使用@Autowired注解进行注入（也可以使用final+@RequiredArgsConstructor）
     */

    @Autowired
    private  UserDetailsService userDetailsService;

    /**
     * 过滤器核心方法，每个HTTP请求都会经过此方法处理
     * 
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @param filterChain 过滤器链，用于继续执行下一个过滤器
     * @throws ServletException Servlet异常
     * @throws IOException IO异常
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        try {
            // 从请求中提取JWT Token
            String token = getTokenFromRequest(request);
            
            // 检查Token是否存在且有效
            // StringUtils.hasText: 判断字符串是否不为空且包含非空白字符
            // jwtUtil.validateToken: 验证Token是否有效（未过期、签名正确等）
            if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) {
                // 从Token中提取用户名
                String username = jwtUtil.getUsernameFromToken(token);
                
                // 确保用户名不为空且当前安全上下文中没有认证信息
                // 避免重复认证
                if(username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    // 根据用户名加载用户详细信息，并创建认证对象
                    // UsernamePasswordAuthenticationToken是Spring Security的认证令牌实现
                    // 第一个参数是主体(principal)，第二个参数是凭证(credentials，这里不需要)，第三个参数是权限(authorities)
                    UsernamePasswordAuthenticationToken authentication =
                            new UsernamePasswordAuthenticationToken(
                                username, 
                                null, // JWT认证不需要密码凭证
                                userDetailsService.loadUserByUsername(username).getAuthorities()
                            );

                    // 设置认证详细信息，包括IP地址、Session ID等
                    // WebAuthenticationDetailsSource用于构建基于Web的认证详情
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    
                    // 将认证信息存储到SecurityContext中，这样在整个请求处理过程中都可以访问到用户信息
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }

        } catch (Exception e) {
            // 捕获认证过程中的任何异常，防止影响正常流程
            // 可以选择记录日志或者进行其他异常处理
            logger.error("无法进行JWT认证：{}", e);
        }
        
        // 继续执行过滤器链中的下一个过滤器
        filterChain.doFilter(request, response);
    }

    /**
     * 从HTTP请求头中提取JWT Token
     * 
     * @param request HTTP请求对象
     * @return 提取到的JWT Token，如果没有则返回null
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 从请求头中获取Authorization字段
        String bearerToken = request.getHeader("Authorization");
        
        // 检查Authorization字段是否存在且以"Bearer "开头
        // JWT Token通常以"Bearer "作为前缀
        if (bearerToken != null && bearerToken.startsWith("Bearer "))
            // 返回Bearer后面的Token部分（去掉前7个字符"Bearer "）
            return bearerToken.substring(7);
        return null;
    }
}